package searchprocessing.aggregate;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import java.util.Comparator;
import java.util.HashMap;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;



import edu.emory.mathcs.backport.java.util.Collections;
import structure.AssetNode;
import structure.EdgeMatchpair;
import structure.NodeMatchpair;
import structure.Relationship;
/**
 * 程式資訊摘要 : 組合比對
 * 版本資訊:1.0
 * 程式設計人員姓名: 朱聖池
 */
public class AggregateMatchUnit {
	private HashMap<String, AssetNode> graph_Node = new HashMap<String, AssetNode>();
	private ArrayList<Relationship> graph_Edge = new ArrayList<Relationship>();
	//找出的相同邊
	public HashMap<String, ArrayList<EdgeMatchpair>> similarEdgeTable = new HashMap<String, ArrayList<EdgeMatchpair>>();
	//儲存
	public HashMap<String, ArrayList<NodeMatchpair>> similarNodeTable = new  HashMap<String, ArrayList<NodeMatchpair>>();
	public HashMap<String,ArrayList<EdgeMatchpair>> findAggregateTable = new HashMap<String,ArrayList<EdgeMatchpair>>();
	public HashMap<String,Double> queryMatch = new HashMap<String,Double>();
	public HashMap<String, Double> similarMatch ;
	private HashMap<String,ArrayList<EdgeMatchpair>> solution_EdgeMatch = new HashMap<String,ArrayList<EdgeMatchpair>>();
	private HashMap<String,ArrayList<NodeMatchpair>> solution_NodeMatch = new HashMap<String,ArrayList<NodeMatchpair>>();
	public double total_compose_score = 0.0 ;
	private HashMap<String,String> convertName = new HashMap<String,String>();
	
	public AggregateMatchUnit(HashMap<String, AssetNode> nodes, ArrayList<Relationship> edges,
			HashMap<String, ArrayList<EdgeMatchpair>> matchedTable, HashMap<String, 
			ArrayList<NodeMatchpair>> nodeMap, HashMap<String, Double> solutionScore, HashMap<String, String> nameTable) {

		setNode(nodes);
		setEdge(edges);
		setSimilarEdgeTable(matchedTable);
		setsimilarNodeTable(nodeMap) ;
		setSimiliarScore(solutionScore);
		setConvertName(nameTable);
		
	}
	
	/**
	 * 比對名稱用，將idVersion轉成Solution 名稱
	 * @param nameTable
	 */
	private void setConvertName(HashMap<String, String> nameTable) {
		this.convertName = nameTable;
	}
	
	/**
	 * 得到query對上data的相似分數table
	 * @return HashMap<String,Double>
	 */
	public HashMap<String,Double> getQueryMatchTable(){
		return queryMatch;
	}
	/**
	 * 儲存相似部分的分數
	 * @param solutionScore
	 */
	public void setSimiliarScore(HashMap<String, Double> solutionScore) {
		this.similarMatch = solutionScore;
		
	}
	/**
	 * key = solutionid_version value=匹配邊的list
	 * @return HashMap<String,ArrayList<EdgeMatchpair>> solution_EdgeMatch
	 */
	public HashMap<String,ArrayList<EdgeMatchpair>> getSolution_EdgeMatchTable(){
		return solution_EdgeMatch;
	}
	/**
	 * key = solutionid_version value=匹配點的list
	 * @return solution_NodeMatch
	 */
	public HashMap<String,ArrayList<NodeMatchpair>> getSolution_NodeMatchTable(){
		return solution_NodeMatch;
	}
	/**
	 * 從similarUnit得來的圖跟點
	 * @param nodeMap
	 */
	private void setsimilarNodeTable(HashMap<String, ArrayList<NodeMatchpair>> nodeMap) {
		this.similarNodeTable = nodeMap ;
	}
	/**
	 * 從similarUnit得來的圖跟邊
	 * @param matchedTable
	 */
	private void setSimilarEdgeTable(HashMap<String, ArrayList<EdgeMatchpair>> matchedTable) {
		this.similarEdgeTable = matchedTable;
	}
	/**
	 * @param query_node
	 * 從資料分析出來，擷取node到此class做比對
	 */
	public void setNode(HashMap<String, AssetNode> query_node){
		this.graph_Node = query_node;
	}
	
	/**
	 * 從資料分析出來，擷取edge到此class做比對
	 * @param query_edge
	 */
	public void setEdge(ArrayList<Relationship> query_edge){
		this.graph_Edge = query_edge;
	}
	/**
	 * 運用相似比對來做組合比對
	 * @throws IOException 
	 */
	public void matched() throws IOException {
		/*
		 * 回傳每一個Graph的相似部分並嘗試組合能否組合query
		 * */

		ArrayList<Map.Entry<String, Double>> connectionOrder = new ArrayList<Map.Entry<String, Double>>();
		HashMap<String, Double> connection = new HashMap<String, Double>();
		
		for(Entry<String, ArrayList<EdgeMatchpair>> solutionKey : similarEdgeTable.entrySet()){
			connection.put(solutionKey.getKey(), (double)solutionKey.getValue().size());	
		}
		//最大連通數排序
		connectionOrder =  mapSort(connection);
		ArrayList<Map.Entry<String, Double>> scoreOrder = new ArrayList<Map.Entry<String, Double>>();
		//最大相似分數排序
		scoreOrder = mapSort(similarMatch) ;
		
		//儲存找到的query邊 對上 的邊(隱含graphID可抽取)
		
		//最佳化組合
		ArrayList<Relationship> queryGraphEdge = (ArrayList<Relationship>) graph_Edge.clone();
		ArrayList<AssetNode> queryGraphNode = exactNode(graph_Node); 
		
		
		String combineSolution = "";
		ArrayList<NodeMatchpair> nodePairs = new ArrayList<NodeMatchpair>();
		ArrayList<EdgeMatchpair> matchedPairs = new ArrayList<EdgeMatchpair>();
		callOpt(combineSolution,queryGraphEdge,queryGraphNode,connectionOrder,matchedPairs,nodePairs);
		mapSort(queryMatch);
		
	}
	
	/**
	 * 擷取出assetNode
	 * @param nodeTable
	 * @return ArrayList<AssetNode>
	 */
	private ArrayList<AssetNode> exactNode(
			HashMap<String, AssetNode> nodeTable) {
		ArrayList<AssetNode> list = new ArrayList<AssetNode>();
		for(Map.Entry<String, AssetNode> node : nodeTable.entrySet()){
			list.add(node.getValue());
		}
		
		return list;
	}

	/**
	 * 遞迴組合
	 * @param combineSolution 
	 * @param edgeSet
	 * @param queryGraphNode 
	 * @param queryGraphNode 
	 * @param solutionOrder
	 * @param unnodePairs2 
	 */
	private void callOpt(String combineSolution, ArrayList<Relationship> edgeSet,
			ArrayList<AssetNode> nodeSet, ArrayList<Entry<String, Double>> solutionOrder
			,ArrayList<EdgeMatchpair> Matchedpairs, ArrayList<NodeMatchpair> unnodePairs) {
		
		//儲存匹配邊的table - ArrayList<EdgeMatchpair> Matchedpiars
		ArrayList<EdgeMatchpair> unMatchedpairs = (ArrayList<EdgeMatchpair>) Matchedpairs.clone();
		ArrayList<NodeMatchpair> unMatchNodePairs = (ArrayList<NodeMatchpair>) unnodePairs.clone();
		//改變前的資料
		ArrayList<Relationship> deEdgeSet = (ArrayList<Relationship>) edgeSet.clone();
		ArrayList<AssetNode> deNodeSet = (ArrayList<AssetNode>) nodeSet.clone();
		
		ArrayList<Entry<String, Double>> deSolution = (ArrayList<Entry<String, Double>>) solutionOrder.clone();
		
		String change = null;
		String unchange = combineSolution;

		
		if(edgeSet.size()==0 && solutionOrder.size()>=0){
			combineSolution = combineSolution.substring(1, combineSolution.length());
			if(combineSolution.split(",").length <= 2){
				solution_EdgeMatch.put(combineSolution, unMatchedpairs);
				solution_NodeMatch.put(combineSolution, unMatchNodePairs);
				double score = calculateAllScore(unMatchedpairs);
				System.out.println("找到一筆組合:"+combineSolution+" -> "+score);
				queryMatch.put(combineSolution, score);
			}
			
		}
		else if(edgeSet.size()>0 && solutionOrder.size()>0){
			for(Map.Entry<String, Double> deGraph : solutionOrder){
				boolean isExist = false;
				
				//去邊
				for(EdgeMatchpair deEdge : similarEdgeTable.get(deGraph.getKey())){
					if(deEdgeSet.remove(deEdge.getQueryEdge())){
						unMatchedpairs.add(deEdge);
						//點的配置圖					
						for(NodeMatchpair deNode : similarNodeTable.get(deGraph.getKey())){
							if(deNodeSet.remove(deEdge.getQueryEdge().getHead()) || 
									deNodeSet.remove(deEdge.getQueryEdge().getTail())){
								unMatchNodePairs.add(deNode);
							}
						}
						
						isExist = true ;
					}
				}
				//去圖
				if(isExist){
					change = deGraph.getKey(); //convertName.get(deGraph.getKey()); , deGraph.getKey()
					deSolution.remove(deGraph.getKey());
					callOpt((unchange+","+change),deEdgeSet,deNodeSet,deSolution,unMatchedpairs,unMatchNodePairs);
				}
				else{//表示該圖無邊可提供
					continue;
				}
				//還原回來
				deEdgeSet = (ArrayList<Relationship>) edgeSet.clone();
				deNodeSet = (ArrayList<AssetNode>) nodeSet.clone();
				deSolution = (ArrayList<Entry<String, Double>>) solutionOrder.clone();
				unchange = combineSolution;
				unMatchedpairs = (ArrayList<EdgeMatchpair>) Matchedpairs.clone();
				unMatchNodePairs = (ArrayList<NodeMatchpair>) unnodePairs.clone();
			}//for end
		}
		else{
			System.out.println("這一條組合無法組合:"+combineSolution+" null");
		}
		
	}
	
	/**
	 * 將similarity matched部分 存入 待aggregate的table
	 * @param key
	 * @param findEdgelist
	 */
	public void setAggregateTable(String key,ArrayList<EdgeMatchpair> findEdgelist) {
		findAggregateTable.put(key,findEdgelist);
	}
	
	/**
	 * 得到最後相符的組合結果
	 * @return HashMap<String,ArrayList<EdgeMatchpair>>
	 */
	public  HashMap<String,ArrayList<EdgeMatchpair>> getAggregateTable() {
		return findAggregateTable;
		
	}
	
	/**
	 * 由大到小排序分數
	 * @param unsortMap
	 * @return ArrayList<Entry<String, Double>>
	 * @throws IOException
	 */
	public ArrayList<Entry<String, Double>> mapSort(HashMap<String, Double> unsortMap) throws IOException{
		//sort
		List<Entry<String, Double>> final_Rank =
	            new ArrayList<Map.Entry<String, Double>>(unsortMap.entrySet());
	        //排序mapsort依分數大小  
        Collections.sort(final_Rank, new Comparator<Map.Entry<String, Double>>(){
        	public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2)
            {
              if ((o2.getValue() - o1.getValue())>0)
                return 1;
              else if((o2.getValue() - o1.getValue())==0)
                return 0;
              else 
                return -1;
            }
        });
        
        /*FileWriter output = new FileWriter("D:\\outlist130.txt" );
		PrintWriter out = new PrintWriter(output) ;
		
        for(int finalsize=0;finalsize<final_Rank.size();finalsize++){
        	//System.out.println(convertName.get(final_Rank.get(finalsize).getKey())
        	//		+"  "+final_Rank.get(finalsize).getValue()) ;
        	out.print(final_Rank.get(finalsize).getKey()+" : "+queryMatch.get(final_Rank.get(finalsize).getKey())) ;
			out.print("\r\n") ;
        	
        }
        output.close();*/
        return (ArrayList<Entry<String, Double>>) final_Rank;
	}

	/**
	 * 計算整體分數(每邊的相似度相乘)
	 * @param edgeMatch2
	 * @return double型態回傳整體分數
	 */
	protected Double calculateAllScore(ArrayList<EdgeMatchpair> edgeMatch) {
		int loseEdge = graph_Edge.size() - edgeMatch.size() ;
		double TotalScore = 0.0 ; // 屬性分數統計

		//平均分數
		if(loseEdge>0){
			double similarScore = 0.0;
			for(int index=0;index<edgeMatch.size();index++){
				similarScore += edgeMatch.get(index).getSimilarEdgeScore();
			}
			TotalScore = similarScore/graph_Edge.size() ;
		}
		else if(loseEdge == 0){
			double similarScore = 0.0;
			for(int index=0;index<edgeMatch.size();index++){
				similarScore+=edgeMatch.get(index).getSimilarEdgeScore();
			}
			TotalScore = 1.0*similarScore/edgeMatch.size() ;
		}
		
		return TotalScore ;
	}
	
}
